package aes256

import (
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"encoding/hex"
	"fmt"
)

var AES256Nonce = make([]byte, 12)

func Encrypt(key, data string) (string, error) {
	secret, err := getKeyByte(key)
	if err != nil {
		return "", err
	}
	encrypt, err := enAES256([]byte(data), secret, AES256Nonce)
	if err != nil {
		return "", err
	}
	return base64Encode(encrypt), nil
}

func Decrypt(key, data string) (string, error) {
	chipertext, err := base64Decode(data)
	if err != nil {
		return "", err
	}
	secret, err := getKeyByte(key)
	if err != nil {
		return "", err
	}
	decrypt, err := dnAES256(chipertext, secret, AES256Nonce)
	if err != nil {
		return "", err
	}
	return string(decrypt), nil
}

// Encrypt ase256 gcm Encrypt.
func enAES256(plaintext, key, nonce []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	aesgcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	ciphertext := aesgcm.Seal(nonce, nonce, plaintext, nil)
	return ciphertext, nil
}

// Decrypt ase256 gcm Decrypt.
func dnAES256(chipertext, key, nonce []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	aesgcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	if len(chipertext) > 12 {
		nonceNew, chipertextNew := chipertext[:12], chipertext[12:]
		if plaintext, err1 := aesgcm.Open(nil, nonceNew, chipertextNew, nil); err1 == nil {
			return plaintext, nil
		}
	}

	plaintext, err := aesgcm.Open(nil, nonce, chipertext, nil)
	if err != nil {
		return nil, err
	}
	return plaintext, nil
}

func base64Decode(src string) ([]byte, error) {
	return base64.StdEncoding.DecodeString(src)
}

func base64Encode(src []byte) string {
	return base64.StdEncoding.EncodeToString(src)
}
func getKeyByte(key string) ([]byte, error) {
	switch len(key) {
	case 32:
		return []byte(key), nil
	case 64:
		return hex.DecodeString(key)
	default:
		return nil, fmt.Errorf("key len is err: %v", len(key))
	}
}
